package com.autumn.cloud.lock.impl;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import com.autumn.cloud.lock.DistributedLock;
import com.autumn.cloud.lock.LockUnitOfWorker;
import com.autumn.cloud.lock.LockUnitOfWorkerResult;
import com.autumn.cloud.lock.UnableLockTimeoutException;

/**
 * 分布式锁实现
 * 
 * @author 老码农
 *
 *         2017-11-23 12:08:56
 */
public class DistributedLockImpl extends AbstractResourceLock implements DistributedLock {

	private final RedissonClient redissonClient;

	public DistributedLockImpl(RedissonClient redissonClient){
		this.redissonClient = redissonClient;
	}

	@Override
	public void lock(String resourceName) throws Exception {
		RLock lock = redissonClient.getLock(resourceName);
		lock.lock();
	}

	@Override
	public void lock(String resourceName, int timeout) throws UnableLockTimeoutException, Exception {
		RLock lock = redissonClient.getLock(resourceName);
		boolean seccess = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
		if (!seccess) {
			throw throwUnableLockTimeoutException(resourceName, timeout);
		}
	}

	@Override
	public void lock(String resourceName, LockUnitOfWorker lockUnitOfWorker) throws Exception {
		RLock lock = redissonClient.getLock(resourceName);
		try {
			lock.lock();
			if (lockUnitOfWorker != null) {
				lockUnitOfWorker.execute();
			}
		} finally {
			lock.unlock();
		}
	}

	@Override
	public void lock(String resourceName, LockUnitOfWorker lockUnitOfWorker, int timeout)
			throws UnableLockTimeoutException, Exception {
		RLock lock = redissonClient.getLock(resourceName);
		boolean seccess = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
		if (seccess) {
			try {
				if (lockUnitOfWorker != null) {
					lockUnitOfWorker.execute();
				}
			} finally {
				lock.unlock();
			}
		} else {
			throw throwUnableLockTimeoutException(resourceName, timeout);
		}
	}

	@Override
	public <TResult> TResult lock(String resourceName, LockUnitOfWorkerResult<TResult> lockUnitOfWorker)
			throws Exception {
		RLock lock = redissonClient.getLock(resourceName);
		try {
			lock.lock();
			if (lockUnitOfWorker != null) {
				return lockUnitOfWorker.executeResult();
			}
			return null;
		} finally {
			lock.unlock();
		}
	}

	@Override
	public <TResult> TResult lock(String resourceName, LockUnitOfWorkerResult<TResult> lockUnitOfWorker, int timeout)
			throws UnableLockTimeoutException, Exception {
		RLock lock = redissonClient.getLock(resourceName);
		boolean seccess = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
		if (seccess) {
			try {
				if (lockUnitOfWorker != null) {
					return lockUnitOfWorker.executeResult();
				}
				return null;
			} finally {
				lock.unlock();
			}
		} else {
			throw throwUnableLockTimeoutException(resourceName, timeout);
		}
	}

	@Override
	public void unlock(String resourceName) throws Exception {
		RLock lock = redissonClient.getLock(resourceName);
		lock.unlock();
	}
}
